/*
 * author: kula <kulasama@gmail.com>
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
#include <syslog.h>
#include <pthread.h>


/**
 * 
 * Description:尾进头出队列，固定大小，入列数据超出大小就踢掉队列头部
 */ 
struct fixedQueue
{
    int size;
    int front;
    int tail;
    void **ppNodes;
    pthread_mutex_t lock; 
};


fixedQueue_t * queue_init(int maxSize)
{
    fixedQueue_t *fq ;
    fq = calloc(1,sizeof(fixedQueue_t));
    pthread_mutex_init(&fq->lock,NULL);
    fq->size=maxSize;
    fq->front = 0;
    fq->tail = 0;
    fq->ppNodes = calloc(maxSize,sizeof(int));
    int i ;
    for(i = 0;i<maxSize;i++)
    {
        *(fq->ppNodes+i) = NULL;
    }
    return fq;
}


/*
 *Description:如果队列头指针等于尾指针，且队列不为空，说明此队列已满
 *
 */
int queue_isFull(fixedQueue_t *fq)
{
    if(fq == NULL)
    {
        printf("ArgumentException...\n");
        return -1;
    }
    return (fq->front == fq->tail && *(fq->ppNodes+fq->front) != NULL);
}

/*
 *Description:如果队列里没数据，说明队列为空
 *
 */
int queue_isEmpty(fixedQueue_t *fq)
{
    if(fq == NULL)
    {
        printf("ArgumentException...\n");
        return -1;
    }
    return (*(fq->ppNodes+fq->front) == NULL);   
}

/*
 *Description:入列操作，将data指针指向的内容加入队列fq中，
 *   size为data指针指向内容所占的内存大小
 *
 */
void* queue_append(fixedQueue_t *fq,void *data)
{
    if(fq == NULL || data== NULL)
    {
        printf("ArgumentException...\n");
        return NULL;
    }
    pthread_mutex_lock(&fq->lock);
    void * ret = NULL;
    if(queue_isFull(fq))
    {            
        ret = *(fq->ppNodes+fq->front);
        *(fq->ppNodes+fq->front) = NULL;
        fq->front = ++fq->front%fq->size;
    }
    *(fq->ppNodes+fq->tail)= data;
    fq->tail = ++fq->tail % fq->size;
    pthread_mutex_unlock(&fq->lock);
    return ret;
}



/*
 *Description:出列函数,将ret指向出列的数据
 *   
 */
void * queue_fetch(fixedQueue_t *fq)
{    
    if(fq == NULL)
    {
        printf("ArgumentException...\n");
        return NULL;
    }
    if(queue_isEmpty(fq))
    {
        return NULL;
    }
    pthread_mutex_lock(&fq->lock);
    void *ret = *(fq->ppNodes+fq->front);
    *(fq->ppNodes + fq->front) = NULL;
    fq->front = ++fq->front%fq->size;
    pthread_mutex_unlock(&fq->lock);
    return ret;
}





/*
 *
 *   打印队列内容，
 *   本函数只供调试用
 */
int printQueue(fixedQueue_t *fq,char * sign)
{
    int i;
    openlog("Thread:",LOG_CONS | LOG_PID,0);
    syslog(LOG_DEBUG,"-------front:%d,tail:%d--------",fq->front,fq->tail);
    for(i=0;i<fq->size;i++)
    {
    	syslog(LOG_DEBUG,"sign:%s,pos:%d,value:%s",sign,i,(char *)fq->ppNodes[i]);
    }
    closelog();
    return 0;
}

int queue_len(fixedQueue_t *fq)
{
	pthread_mutex_lock(&fq->lock);
	int count = 0;
	int i;
	for(i=0; i<fq->size; i++)
	{
		if(*(fq->ppNodes+i) != NULL)
		{
			count++;
		}
	}
	pthread_mutex_unlock(&fq->lock);
	return count;
	
}

/*---------------------test code----------------------------------------------*/

int queue_case1()
{
	fixedQueue_t *fq = queue_init(1000);
	int i;
	int sign = 544;
	for(i =0;i<sign;i++)
	{
		char *s = calloc(20,sizeof(char));
		sprintf(s,"test%d",i);
		queue_append(fq,s);
	}
	int m = queue_len(fq);
	if(m == sign)
	{
		return 0;
	}
	else
	{
		printf("queue_case 1 failure\n");
		return 1;
	}
	
}

void queue_test()
{
	int i = 0;
	i += queue_case1();
	if(i == 0)
	{
		printf("queue test ok\n");
	}
	else
	{
		printf("queue test failure\n");
	}
}




